package fem2.pre_and_post;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.StringTokenizer;

import fem2.MeshGenerator;
import fem2.NotImplementedError;

/**
 * Mesh generator from Hyplas input files
 * 
 * @author hbui
 * 
 */
public class HyplasMeshGenerator extends MeshGenerator {

	private static final String NODE_BLOCK_KW = "NODE_COORDINATES";
	private static final String ELEMENT_BLOCK_KW = "ELEMENTS";
	private static final int ELEMENT_BASE_INDEX = 1;

	private static final int[][] mapConnectivity = new int[][] { { 0, 2, 4, 6, 1, 3, 5, 7 } };

	private File file;

	public HyplasMeshGenerator(String fileName) {
		file = new File(fileName);
	}

	@Override
	public ArrayList<double[]> getNodes(int dim) {
		ArrayList<double[]> nodes = new ArrayList<double[]>();
		Scanner scanner = null;
		try {
			scanner = new Scanner(new FileReader(file));
		} catch (FileNotFoundException e) {
			throw new Error("File not found: " + e.getMessage());
		}
		try {
			boolean isBlock = false;
			int cnt = 0, numNodes = 0;
			while (scanner.hasNextLine()) {
				String line = scanner.nextLine();
				/*
				 * if meet the empty line, then skip
				 */
				if (line.compareTo("") == 0) {
					continue;
				}
				StringTokenizer s = new StringTokenizer(line);

				/*
				 * check if current position fall in a block
				 */
				if (!isBlock) {
					/*
					 * search for keyword MESH
					 */
					if (s.nextToken().compareTo(NODE_BLOCK_KW) == 0) {
						isBlock = true;
						numNodes = Integer.parseInt(s.nextToken());

						if (s.nextToken().compareTo("CARTESIAN") != 0) {
							throw new Error("coordinates other than Cartesian is not supported yet");
						}
					}
				} else {
					/*
					 * skip the index
					 */
					s.nextToken();
					/*
					 * read node data
					 */
					double[] v = new double[dim];
					for (int i = 0; i < dim; i++) {
						v[i] = Double.parseDouble(s.nextToken());
					}
					nodes.add(v);
					/*
					 * increment to next line
					 */
					cnt++;

					if (cnt == numNodes) {
						isBlock = false;
					}
				}

			}
		} finally {
			/*
			 * close the line scanner
			 */
			scanner.close();
		}
		return nodes;
	}

	@Override
	public ArrayList<ArrayList<Integer>> getConnectivities() {
		ArrayList<ArrayList<Integer>> connectivities = new ArrayList<ArrayList<Integer>>();
		Scanner scanner = null;
		try {
			scanner = new Scanner(new FileReader(file));
		} catch (FileNotFoundException e) {
			throw new Error("File not found: " + e.getMessage());
		}
		try {
			boolean isBlock = false;
			int cnt = 0, numElems = 0;
			while (scanner.hasNextLine()) {
				String line = scanner.nextLine();
				/*
				 * if meet the empty line, then skip
				 */
				if (line.compareTo("") == 0) {
					continue;
				}
				StringTokenizer s = new StringTokenizer(line);
				/*
				 * check if current position fall in a block
				 */
				if (!isBlock) {
					/*
					 * search for keyword
					 */
					if (s.nextToken().compareTo(ELEMENT_BLOCK_KW) == 0) {
						isBlock = true;
						/*
						 * read the number of elements in current block
						 */
						numElems = Integer.parseInt(s.nextToken());
					}
				} else {
					/*
					 * skip the index
					 */
					s.nextToken();
					/*
					 * skip the material
					 */
					s.nextToken();
					/*
					 * read connectivity data
					 */
					ArrayList<Integer> e = new ArrayList<Integer>();
					while (s.hasMoreTokens()) {
						e.add(Integer.parseInt(s.nextToken()) - ELEMENT_BASE_INDEX);
					}
					rearrangeConnectivity(e);
					connectivities.add(e);

					/*
					 * increment to next line
					 */
					cnt++;

					if (cnt == numElems) {
						isBlock = false;
					}
				}
			}
		} finally {
			/*
			 * close the line scanner
			 */
			scanner.close();
		}
		return connectivities;
	}

	/**
	 * rearrange the connectivites since in hyplas use different sequence of
	 * nodes
	 * 
	 * @param con
	 */
	private void rearrangeConnectivity(ArrayList<Integer> con) {
		if (con.size() == 8) {
			int[] con1 = new int[8];
			for (int i = 0; i < 8; i++) {
				con1[i] = con.get(mapConnectivity[0][i]);
			}
			for (int i = 0; i < 8; i++) {
				con.set(i, con1[i]);
			}
		} else {
			/*
			 * TODO
			 */
			throw new NotImplementedError();
		}
	}
}
